#include "PhiolLocalDeviceManager.h"
#include "PhiolRemoteDeviceManager.h"
#include "PhiolSpatial.h"
#include "PhiolTemperatureSensor.h"

#include <map> 
#include <assert.h> 
#include <stdio.h>

#if _WIN32
	#include <Windows.h>
#else
	#include <unistd.h>
	#include <sys/timeb.h>
	#include <time.h>
	#include <sys/time.h>
#endif

// A utility class to provide cross-platform sleep and simple time methods
class Utils
{
public:
	static void sleep( unsigned int _Milliseconds );
	static unsigned long long int getTickFrequency();
	static unsigned long long int getTimeAsTicks();
	static unsigned int getTimeAsMilliseconds();

private:
	static unsigned long long int mInitialTickCount;
};



int i = 0;
class DebugDeviceListener : public Phiol::Device::Listener
{
public:
	void onDeviceChanged( Phiol::Device* device ) 
	{
		switch ( device->getType() )
		{
			case Phiol::Device::kSpatial:
			{
				Phiol::Spatial* spatial = static_cast<Phiol::Spatial*>(device);
				printf("%s\n", spatial->toString().c_str() );

				i++;
				if ( i==20 )
				{
					if ( !spatial->setDataRateInMs( 400 ) )
						printf("\n\nFAILED TO SET RATE\n\n");
				}	
			}
			break;

			case Phiol::Device::kTemperatureSensor:
			{
				Phiol::TemperatureSensor* temperatureSensor = static_cast<Phiol::TemperatureSensor*>(device);
				printf("%s\n", temperatureSensor->toString().c_str() );

				i++;
				if ( i==20 )
				{
					temperatureSensor->getThermocouples()[0]->setType( Phiol::TemperatureSensor::Thermocouple::E_Type );
				}	
			}
			break;
		}
	}
};

class DebugDeviceManagerListener : public Phiol::DeviceManager::Listener
{
public:
	virtual void onDeviceConnected( Phiol::DeviceManager* deviceManager, Phiol::Device* device )
	{
		printf("Device %d %d - Connected\n", device->getSerialNumber(), device->isAttached() );
		
		// Create a listener for the Device, register it and remember it
		Phiol::Device::Listener* listener = new DebugDeviceListener();
		mListeners.insert( std::make_pair( device, listener ) );
		device->addListener( listener );
	}

	virtual void onDeviceDisconnecting( Phiol::DeviceManager* deviceManager, Phiol::Device* device )
	{
		printf("Device %d %d - Disconnecting\n", device->getSerialNumber(), device->isAttached() );
		
		// Retrieve the listener we created for the Device, unregister it, delete it and forget it
		std::map<Phiol::Device*, Phiol::Device::Listener*>::iterator itr = mListeners.find( device );
		assert( itr!=mListeners.end() );
		Phiol::Device::Listener* listener = (*itr).second;
		device->removeListener( listener );
		mListeners.erase( itr );
		delete listener;
	}

private:
	std::map<Phiol::Device*, Phiol::Device::Listener*> mListeners;	
};

int main( int argc, char** argv )
{
	Phiol::LocalDeviceManager deviceManager;
	//Phiol::RemoteDeviceManager deviceManager( "Machine d'Audrey", "" );
	//Phiol::RemoteDeviceManager deviceManager( "192.168.1.56", 5001, "" );
	
//	printf("version: %s\n", deviceManager.getLibraryVersion() );(

	DebugDeviceManagerListener listener;
	deviceManager.addListener( &listener );
	
	bool up = true;
	while ( true )
	{
		if ( up )
			deviceManager.update();
		Utils::sleep( 100 );
		printf(".");
		fflush( stdout );
	}

	return 0;
}

// Utils class implementation
void Utils::sleep( unsigned int _Milliseconds )
{
#if _WIN32
	::Sleep( _Milliseconds );
#else
	struct timespec l_TimeSpec;
	l_TimeSpec.tv_sec = _Milliseconds / 1000;
	l_TimeSpec.tv_nsec = (_Milliseconds % 1000) * 1000000;
	struct timespec l_Ret;
	nanosleep(&l_TimeSpec,&l_Ret);
#endif
}

unsigned long long int Utils::getTickFrequency()
{
#if _WIN32
	LARGE_INTEGER frequency;
	QueryPerformanceFrequency(&frequency);
	return frequency.QuadPart;
#else
	// The gettimeofday function returns the time in microseconds. So it's frequency is 1,000,000.
	return 1000000;
#endif
}

unsigned long long int Utils::getTimeAsTicks()
{
	unsigned long long int tickCount;
#if _WIN32
	LARGE_INTEGER l;
	QueryPerformanceCounter(&l);
	tickCount = l.QuadPart;
#else
	struct timeval p;
	gettimeofday(&p, NULL);	// Gets the time since the Epoch (00:00:00 UTC, January 1, 1970) in sec, and microsec
	tickCount = (p.tv_sec * 1000LL * 1000LL) + p.tv_usec;
#endif
	if ( mInitialTickCount==0xffffffffffffffffLL )
		mInitialTickCount = tickCount;
	tickCount -= mInitialTickCount;
	return tickCount;
}

unsigned int Utils::getTimeAsMilliseconds()
{
	unsigned int millecondsTime = static_cast<unsigned int>( (getTimeAsTicks() * 1000) / getTickFrequency() );
	return millecondsTime;
}

unsigned long long int Utils::mInitialTickCount = 0xffffffffffffffffLL;
